<template>
	<!-- 查询表单 -->
	<CSearch
		v-model="searchParam"
		v-if="searchParamIf"
		v-show="isShowSearch"
		:searchLabelWidth="searchLabelWidth"
		:searchItems="searchColumns"
		:searchTriggerMode="searchTriggerMode"
		v-loading="dictLoading"
		@reset="reset"
		@search="initPageNoSearch"
	>
		<!-- 递归传递插槽！！！ -->
		<template v-for="slotName in Object.keys($slots)" #[slotName]="scope">
			<slot :name="slotName" v-bind="scope" />
		</template>
	</CSearch>
	<div :class="['card', 'table', { 'no-full-table': isFullTable }]">
		<!-- 表格头部 操作按钮 -->
		<div v-if="tableHeaderEnable" class="table-header">
			<div class="header-button-lf">
				<template v-for="(slotName, index) in tableHeaderSlots" :key="index">
					<slot
						name="expand"
						v-if="slotName === 'expand' && expandEnable"
						:selectedListIds="selectedListIds"
						:selectList="selectedList"
						:isSelected="isSelected"
					>
						<el-button type="primary" plain @click="toggleRowExpansion">展开/折叠</el-button>
					</slot>
					<slot
						name="add"
						v-else-if="slotName === 'add' && addEnable && addHandler"
						:selectedListIds="selectedListIds"
						:selectList="selectedList"
						:isSelected="isSelected"
					>
						<el-button type="primary" plain @click.stop="onAddHandler">新增</el-button>
					</slot>
					<slot
						name="batchDelete"
						v-else-if="slotName === 'batchDelete' && batchDeleteEnable && selectionEnable && apiBatchDelete"
						:selectedListIds="selectedListIds"
						:selectList="selectedList"
						:isSelected="isSelected"
					>
						<el-button type="danger" plain :disabled="!isSelected" @click.stop="onBatchDeleteHandler"> 删除 </el-button>
					</slot>
					<slot v-else :name="slotName" :selectedListIds="selectedListIds" :selectList="selectedList" :isSelected="isSelected">
					</slot>
				</template>
			</div>
			<div class="header-button-ri">
				<el-tooltip class="box-item" effect="dark" content="刷新" placement="top">
					<el-button :icon="Refresh" circle @click="search"> </el-button>
				</el-tooltip>
				<el-tooltip class="box-item" effect="dark" content="打印" placement="top">
					<el-button :icon="Printer" circle @click="handlePrint"> </el-button>
				</el-tooltip>
				<el-tooltip class="box-item" effect="dark" content="列设置" placement="top">
					<el-button ref="popoverColSettingRef" :icon="Operation" circle @click="openPopoverColSetting"> </el-button>
				</el-tooltip>
				<el-button :icon="Search" circle v-if="searchParamIf" @click="isShowSearch = !isShowSearch"> </el-button>
			</div>
		</div>
		<!-- 表格主体 -->
		<el-table
			ref="tableRef"
			v-loading="loading || dictLoading"
			:data="tableData"
			:rowKey="rowKey"
			:border="border"
			v-bind="$attrs"
			@selection-change="selectionChange"
		>
			<!-- 多选列 -->
			<el-table-column v-if="selectionEnable" type="selection" />

			<template v-for="(item, index) in tableColumns" :key="index">
				<!-- 序号列 -->
				<el-table-column
					v-if="item.colEnable && item.colShow && item.prop === '#'"
					width="80"
					align="center"
					show-overflow-tooltip
					v-bind="item"
				>
					<template #default="{ $index }">
						{{ genIndex($index) }}
					</template>
				</el-table-column>

				<el-table-column v-else-if="item.colEnable && item.colShow" show-overflow-tooltip v-bind="item">
					<template #header="scope">
						<!-- 列头部插槽 -->
						<slot :name="'header_' + item.prop" v-bind="scope">
							{{ scope.column.label }}
						</slot>
						<el-tooltip v-if="item.alert" effect="dark" :content="item.alert" placement="top">
							<el-icon><InfoFilled /></el-icon>
						</el-tooltip>
					</template>
					<template #default="scope">
						<!-- 列内容插槽 -->
						<slot :name="'col_' + item.prop" v-bind="scope">
							<component :is="componentInfo" :row="scope.row" :col="item"></component>
						</slot>
					</template>
				</el-table-column>
			</template>

			<!-- 操作列 -->
			<el-table-column
				v-if="operationColEnable && operationColSlots.length"
				label="操作"
				fixed="right"
				:width="operationColWidth"
			>
				<template #default="scope">
					<template v-if="scope.row._noOperation !== true">
						<!-- 操作列插槽 -->
						<template v-for="(slotName, index) in operationColSlots" :key="index">
							<slot
								name="edit"
								v-bind="scope"
								v-if="slotName === 'edit' && editEnable && editHandler && scope.row._noEdit !== true"
							>
								<el-button type="primary" link @click.stop="onEditHandler(scope.row)">编辑</el-button>
							</slot>
							<slot
								name="detail"
								v-bind="scope"
								v-else-if="slotName === 'detail' && detailEnable && detailHandler && scope.row._noDetail !== true"
							>
								<el-button type="primary" link @click.stop="onDetailHandler(scope.row)">详情</el-button>
							</slot>
							<slot
								name="delete"
								v-bind="scope"
								v-else-if="slotName === 'delete' && deleteEnable && apiDelete && scope.row._noDelete !== true"
							>
								<el-button type="danger" link @click.stop="onDeleteHandler(scope.row)">删除</el-button>
							</slot>
							<slot v-else :name="slotName" v-bind="scope"> </slot>
						</template>
					</template>
				</template>
			</el-table-column>

			<template #empty>
				<div class="table-empty">
					<img src="@/assets/images/notData.png" alt="notData" />
					<div>暂无数据</div>
				</div>
			</template>
		</el-table>
		<!-- 分页组件 -->
		<Pagination
			v-if="pagination"
			:pageable="pageable"
			:handleSizeChange="handleSizeChange"
			:handleCurrentChange="handleCurrentChange"
		/>
	</div>
	<!-- 列设置 -->
	<PopoverColSetting
		ref="popovercolRef"
		:buttonRef="popoverColSettingRef"
		v-model="tableColumns"
		@table-ref-do-layout="tableRefDoLayout"
	/>
</template>

<script setup lang="tsx" name="CTable">
import { ref, watch, computed, onBeforeMount } from 'vue'
import { ElTable, ElMessageBox, ElMessage } from 'element-plus'
import { useTable } from './hooks/useTable'
import { useSelection } from './hooks/useSelection'
import { Refresh, Printer, Operation, Search, InfoFilled } from '@element-plus/icons-vue'
import { ColumnProps, ColType } from '@/components/CTable/interface'
// import { filterEnum, formatValue } from '@/utils/util'
import { filterDict, deepClone } from '@/utils/util'
import dict from '@/utils/dict/index'
// import SearchForm from '@/components/SearchForm/index.vue'
import CSearch, { SearchTriggerMode } from '@/components/CSearch/index.vue'
import Pagination from './components/Pagination.vue'
// import { useHandleData } from '@/hooks/useHandleData'
import PopoverColSetting from './components/PopoverColSetting.vue'
import printJS from 'print-js'

interface CTableProps {
	columnList: ColumnProps[] // 列信息
	rowKey?: string // 唯一 key
	border?: boolean // 表格边框
	printTitle?: string // 打印标题 ==> 非必传（默认为 列表）
	selectionEnable?: boolean // 是否多选
	indexEnable?: boolean // 是否显示序号
	searchLabelWidth?: string // 搜索 label 宽度
	operationColWidth?: string // 操作列的宽度
	isFullTable?: boolean // 外层是否无高度容器，需要表格自行撑开无数据时的情况
	apiSearch: (...params: any[]) => Promise<any> // 搜索 api
	apiDelete?: (...params: any[]) => Promise<any> // 删除 api
	apiBatchDelete?: (...params: any[]) => Promise<any> // 批量删除 api
	addHandler?: Function // 添加按钮处理函数
	editHandler?: Function // 编辑按钮处理函数
	detailHandler?: Function // 详情按钮处理函数

	/* 搜索 */
	initParam?: Record<string, any> // 初始查询参数，通常和外部组件进行联动，重置不会恢复
	initQueryEnable?: boolean // 初始化查询
	searchTriggerMode?: SearchTriggerMode // 搜索触发模式

	/* 是否显示某些操作 */
	searchEnable?: boolean // 是否能开启搜索
	tableHeaderEnable?: boolean // 是否显示表格头
	operationColEnable?: boolean // 是否显示操作列
	expandEnable?: boolean // 展开
	editEnable?: boolean // 编辑
	addEnable?: boolean // 添加
	deleteEnable?: boolean // 删除
	batchDeleteEnable?: boolean // 批量删除
	detailEnable?: boolean // 详情
	pagination?: boolean // 分页

	/* 表格头插槽定义 */
	tableHeaderSlots?: string[]
	/* 操作列插槽定义 */
	operationColSlots?: string[]
	/* 权限 */
	authKeyConfig?: {
		// 按钮权限标识
		add: string
		edit: string
		detail: string
		delete: string
		// 列权限标识
		// [key: string]: string
	} // 权限标识配置
	// authKeys: Set<string> // 权限标识
	// 表格自带参数
	// [key: string]: any
}

// 表格 DOM 元素
const tableRef = ref<InstanceType<typeof ElTable>>()

// 是否显示搜索模块
const isShowSearch = ref<boolean>(true)
// 接受父组件参数，配置默认值
const props = withDefaults(defineProps<CTableProps>(), {
	printTitle: '列表', // 打印标题 ==> 非必传（默认为 列表）
	selectionEnable: false, // 是否多选
	indexEnable: false, // 是否显示序号
	searchLabelWidth: '100px', // 搜索 label 宽度
	operationColWidth: '160px', // 操作列的宽度
	searchEnable: true, // 是否能开启搜索
	tableHeaderEnable: true, // 是否显示表格头
	operationColEnable: true, // 是否显示操作列
	expandEnable: false, // 展开
	editEnable: true, // 编辑
	addEnable: false, // 添加
	deleteEnable: true,
	batchDeleteEnable: true,
	detailEnable: true, // 详情
	initQueryEnable: true,
	rowKey: '',
	pagination: true,
	searchTriggerMode: 'changeEvent',
	border: false,
	isFullTable: false,
	tableHeaderSlots: () => ['expand', 'add', 'batchDelete'],
	operationColSlots: () => ['edit', 'detail', 'delete']
})
// 表格多选 Hooks
const { selectionChange, selectedList, selectedListIds, isSelected } = useSelection(props.rowKey)

// 清空选中数据列表
const clearSelection = () => tableRef.value!.clearSelection()

// 获取编号
const genIndex = (index: number) => {
	// return index + 1 + pageable.value.pageSize * (pageable.value.pageNo - 1)
	return index + 1
}

// 表格操作 Hooks
const {
	loading,
	tableData,
	pageable,
	searchParam,
	searchInitParam,
	initPageNoSearch,
	search,
	reset,
	handleSizeChange,
	handleCurrentChange
} = useTable(props.apiSearch, props.initParam, props.pagination, props.initQueryEnable)

// 监听页面 initParam 改化，重新获取表格数据
watch(
	() => props.initParam,
	() => {
		// 立刻执行搜索
		initPageNoSearch()
	},
	{ deep: true }
)

/* 组件信息 */
const componentInfo = (scope: any): any => {
	const col = scope.col as ColumnProps
	const prop = col.prop
	const dictData = col._dictData
	const colProps = col.colProps || {}
	const row = scope.row
	/* 组件映射，此对象放里面方便后面根据 item 数据修改*/
	const compMap: Record<ColType, () => any> = {
		text() {
			if (dictData) {
				return <dict-text value={row[prop]} options={dictData} {...colProps}></dict-text>
			}
			return <span>{row[prop]}</span>
		},
		tag() {
			if (dictData) {
				return <dict-tag value={row[prop]} options={dictData} {...colProps}></dict-tag>
			}
			return <el-tag {...colProps}>{row[prop]}</el-tag>
		}
	}

	let result
	if (col.colType) {
		result = compMap[col.colType]()
	} else {
		// 默认
		result = compMap.text()
	}
	return result
}

// 表格列配置项处理
const columnsTemp = props.columnList.map(item => {
	return {
		colEnable: true,
		colShow: true,
		searchOrder: 1,
		...item
	}
})
if (props.indexEnable) {
	// 头部添加下标列
	columnsTemp.splice(0, 0, {
		colEnable: true,
		colShow: true,
		searchOrder: 1,
		prop: '#',
		label: '#'
	})
}
const tableColumns = ref<ColumnProps[]>(columnsTemp)
/**添加 */
const onAddHandler = () => {
	props.addHandler!()
}

/**编辑 */
const onEditHandler = (row: any) => {
	props.editHandler!(deepClone(row))
}

/**详情 */
const onDetailHandler = (row: any) => {
	props.detailHandler!(deepClone(row))
}

/**删除 */
const onDeleteHandler = (row: any) => {
	ElMessageBox.confirm(`是否确认删除数据项?`, '温馨提示', {
		confirmButtonText: '确定',
		cancelButtonText: '取消',
		type: 'warning',
		draggable: true
	})
		.then(() => {
			props.apiDelete!({ id: row.id }, deepClone(row)).then(() => {
				ElMessage.success('删除数据项成功!')
				search()
			})
		})
		.catch(() => {})
}
/** 批量删除按钮操作 */
const onBatchDeleteHandler = () => {
	ElMessageBox.confirm(`是否确认删除数据项?`, '温馨提示', {
		confirmButtonText: '确定',
		cancelButtonText: '取消',
		type: 'warning',
		draggable: true
	})
		.then(() => {
			props.apiBatchDelete!(deepClone(selectedListIds.value), deepClone(selectedList.value)).then(() => {
				ElMessage.success('删除数据项成功!')
				search()
			})
		})
		.catch(() => {})
}

// 排序跟新列表
const tableRefDoLayout = () => {
	tableRef.value?.doLayout()
}

// 是否显示搜索
const searchParamIf = props.searchEnable && tableColumns.value.some(item => item.searchEnable)
let searchColumns = ref<ColumnProps[]>([])
// 字典加载
let dictLoading = ref(false)
onBeforeMount(() => {
	// 如果当前 enum 为后台数据 需要请求数据，则调用该请求接口，获取enum数据
	const apiArr: Promise<any>[] = []
	for (const item of tableColumns.value) {
		if (item.dict) {
			if (typeof item.dict === 'function') {
				apiArr.push(item.dict().then(data => (item._dictData = data)))
			} else if (typeof item.dict === 'string') {
				apiArr.push(dict.$cache.getDict(item.dict).then(data => (item._dictData = data)))
			} else {
				item._dictData = item.dict
			}
		}
	}
	dictLoading.value = true
	Promise.all(apiArr)
		.then(() => {
			if (props.searchEnable) {
				// 过滤需要搜索的配置项，并排序
				const searchColumnList = tableColumns.value
					.filter(item => item.searchEnable)
					.sort((a, b) => a.searchOrder! - b.searchOrder!)
				// 设置搜索表单的默认值
				searchColumnList.forEach(column => {
					if (column.searchDefault !== undefined && column.searchDefault !== null) {
						searchInitParam.value[column.prop!] = column.searchDefault
					}
				})
				searchColumns.value = searchColumnList
			}
		})
		// .catch(() => {
		// 	ElMessage.error('字典接口异常')
		// })
		.finally(() => {
			dictLoading.value = false
			// 初始默认值后请求接口
			reset()
		})
})
// 切换树形展开
const expandAll = ref(false)
const toggleRowExpansion = () => {
	if (!props.rowKey) {
		return
	}
	const isExpansion = (expandAll.value = !expandAll.value)
	toggleRowExpansion_forAll(tableData.value, isExpansion)
}
const toggleRowExpansion_forAll = (data: any[], isExpansion: boolean) => {
	data.forEach(item => {
		tableRef.value?.toggleRowExpansion(item, isExpansion)
		if (item.children !== undefined && item.children !== null) {
			toggleRowExpansion_forAll(item.children, isExpansion)
		}
	})
}

// 设置
const popoverColSettingRef = ref()

// 列设置
const popovercolRef = ref()
// 过滤掉不需要设置显隐的列
// 排序
const colSetting = () => {
	let itmeL: Array<Partial<ColumnProps>> = []
	let itmeCen: Array<Partial<ColumnProps>> = []
	let itmeR: Array<Partial<ColumnProps>> = []
	tableColumns.value.forEach((element: Partial<ColumnProps>) => {
		if (
			element.type !== 'selection' &&
			element.type !== 'index' &&
			element.type !== 'expand' &&
			!element.expandEnable &&
			element.colEnable &&
			element.colShow
		) {
			if (element?.fixed === 'left') {
				itmeL.push(element)
			} else if (element?.fixed === 'right') {
				itmeR.push(element)
			} else {
				itmeCen.push(element)
			}
		}
	})

	return [...itmeL, ...itmeCen, ...itmeR]
}

const openPopoverColSetting = () => {
	popovercolRef.value.onClickOutside()
}

// 处理打印数据（把后台返回的字典值根据 enum 做转换）
const printData = computed(() => {
	let printDataList = JSON.parse(JSON.stringify(selectedList.value.length ? selectedList.value : tableData.value))
	// 处理有字典的
	colSetting()
		.filter(item => item._dictData)
		.forEach(colItem => {
			printDataList.forEach((tableItem: any) => {
				tableItem[colItem.prop!] = filterDict(tableItem[colItem.prop!], colItem._dictData)
			})
		})
	// 处理序号
	if (props.indexEnable) {
		colSetting()
			.filter(item => item.prop === '#')
			.forEach(colItem => {
				printDataList.forEach((tableItem: any, index: number) => {
					tableItem[colItem.prop!] = genIndex(index)
				})
			})
	}

	return printDataList
})

// 打印表格数据
const handlePrint = () => {
	printJS({
		printable: printData.value,
		header: `<div style="display: flex;flex-direction: column;text-align: center"><h2>${props.printTitle}</h2></div>`,
		properties: colSetting().map((item: Partial<ColumnProps>) => {
			return {
				field: item.prop,
				displayName: item.label
			}
		}),
		type: 'json',
		gridHeaderStyle:
			'border: 1px solid #ebeef5;height: 45px;font-size: 14px;color: #232425;text-align: center;background-color: #fafafa;',
		gridStyle: 'border: 1px solid #ebeef5;height: 40px;font-size: 14px;color: #494b4e;text-align: center'
	})
}

// 暴露给父组件的参数和方法(外部需要什么，都可以从这里暴露出去)
defineExpose({
	// 搜索的参数
	searchParam,
	// 分页参数
	pageable,
	// 初始到第一页搜索
	initPageNoSearch,
	// 保持分页搜索条件搜索
	search,
	// 重置
	reset,
	onAddHandler,
	onEditHandler,
	onDetailHandler,
	onDeleteHandler,
	onBatchDeleteHandler,
	/* --- 多选 */
	// 清空多选
	clearSelection,
	// 选中的行
	selectedList,
	// 选中行的唯一标识，必须设置 rowKey
	selectedListIds,
	// 是否选中
	isSelected
})
</script>
